import { Graph, Node } from '@antv/x6';
import { DagreLayout } from '@antv/layout';
import { NODE_WIDTH, RANK_SEP, NODE_SEP, ConditionTypeEnum } from '../constant';

const rankdir = 'LR';
const align = undefined;
const nodeSize = NODE_WIDTH;
const ranksep = RANK_SEP;
const nodesep = NODE_SEP;
const controlPoints = false;
const begin = [40, 40];

export const forceLayout = (flowGraph, cfg = {}) => {
  antvDagreLayout(flowGraph, cfg);
};

/**
 * 使用AntV的图布局包实现布局
 * @param flowGraph 图实例
 * @param cfg 配置
 */
function antvDagreLayout(flowGraph, cfg = {}) {
  const dagreLayout = new DagreLayout({
    begin,
    type: 'dagre',
    rankdir,
    align,
    nodeSize,
    ranksep,
    nodesep,
    controlPoints,
  });

  dagreLayout.updateCfg({
    ...cfg,
  });

  const { nodes: newNodes } = dagreLayout.layout({
    nodes: flowGraph.getNodes().map((node) => {
      node.setZIndex(1);
      return node.toJSON();
    }),
    edges: flowGraph.getEdges().map((edge) => {
      edge.setZIndex(0);
      return edge.toJSON();
    }),
  });

  flowGraph.freeze();

  newNodes?.forEach((node) => {
    const cell = flowGraph.getCellById(node.id);
    if (cell) {
      cell.position(node.x, node.y);
    }
  });

  fineTuneLayer(flowGraph);

  flowGraph.unfreeze();
}

/**
 * 解决Dagre布局部分节点层次过低问题
 * @param flowGraph 图实例
 */
function fineTuneLayer(flowGraph) {
  let queue = flowGraph.getRootNodes();
  let layer = 0;

  while (queue.length) {
    let cells = [];
    queue.forEach((next) => {
      const { y } = next.position();
      if (y < layer * 100) {
        next.position(next.position().x, layer * 100);
      }
      cells.push(...next.getSuccessors());
    });
    queue = cells;
    layer++;
  }
}

/**
 * 微调Catch节点
 * @param flowGraph 图实例
 */
function fineTuneCatchNodes(flowGraph) {
  const catchNodes = flowGraph.getNodes().filter(node => {
    const data = node.getData();
    return data && data.model && data.model.type === ConditionTypeEnum.CATCH;
  });

  catchNodes.forEach(catchNode => {
    beforeCatchStart(flowGraph, catchNode);
    afterCatchEnd(flowGraph, catchNode);
  });
}

/**
 * Catch开始前的节点调整
 * @param flowGraph 图实例
 * @param catchStart Catch开始节点
 */
function beforeCatchStart(flowGraph, catchStart) {
  const predecessors = catchStart.getPredecessors();
  predecessors.forEach(predecessor => {
    const { x, y } = predecessor.position();
    const catchX = catchStart.position().x;
    if (x > catchX - 100) {
      predecessor.position(catchX - 100, y);
    }
  });
}

/**
 * Catch结束后的节点调整
 * @param flowGraph 图实例
 * @param catchEnd Catch结束节点
 */
function afterCatchEnd(flowGraph, catchEnd) {
  const successors = catchEnd.getSuccessors();
  successors.forEach(successor => {
    const { x, y } = successor.position();
    const catchX = catchEnd.position().x;
    if (x < catchX + 100) {
      successor.position(catchX + 100, y);
    }
  });
}

/**
 * 获取节点顺序
 * @param flowGraph 图实例
 */
function getNodeOrderFrom(flowGraph) {
  return flowGraph.getNodes().map(node => node.id);
} 